/**
 * 
 */
package edu.rice.myxo.olexii1;

import java.io.*;
import java.util.*;

import edu.rice.myxo.utils.*;

/**
 * @author Haiyang Zhang This class contains external parameters All parameters
 *         are public and can be accessed from any class
 * 
 */
public class Global {

	/**
	 * This method reads in parameters from a parameter file and assign the
	 * value according to parameter name. The parameter file should have the
	 * format of: parameter_name=parameter_value
	 * 
	 * @param filename
	 * @throws IOException
	 * @throws SecurityException
	 * @throws NoSuchFieldException
	 * @throws IllegalArgumentException
	 * @throws IllegalAccessException
	 */
	public static void getParam(String filename) throws IOException,
			SecurityException, NoSuchFieldException, IllegalArgumentException,
			IllegalAccessException {
		File file = new File(filename);
		if (file.exists()) {
			Scanner sc = new Scanner(file);
			while (sc.hasNext()) {
				String paraline = sc.nextLine();
				if (paraline.contains("#")) {
					continue;
				}
				Scanner line = new Scanner(paraline).useDelimiter("=");
				String name = line.next();
				if (line.hasNextBoolean()) {
					Global.class.getField(name).setBoolean(null,
							line.nextBoolean());
				} else if (line.hasNextInt()) {
					Global.class.getField(name).setInt(null, line.nextInt());
				} else if (line.hasNextDouble()) {
					Global.class.getField(name).setDouble(null,
							line.nextDouble());
				}
			}
			sc.close();
			if (reversingTime != 0) {
				vPhase = 2 * Math.PI / reversingTime;
			}
			coneAngle = Math.toRadians(coneAngle);
		} else {
			System.out.println("Configuration file does noe exist!");
		}
	}

	/**
	 * This method write all global parameters to a file specified by the
	 * filename. The file has the format of: parameter_name=parameter_value
	 * 
	 * @param dirname
	 * @throws IOException
	 * @throws IllegalArgumentException
	 * @throws SecurityException
	 * @throws IllegalAccessException
	 */
	public static void writeParam(String dirname) throws IOException,
			IllegalArgumentException, SecurityException, IllegalAccessException {
		String filename = dirname + "//" + "config.txt";
		FileWriter fw = new FileWriter(filename);
		PrintWriter pw = new PrintWriter(fw);
		for (int i = 0; i < Global.class.getFields().length; i++) {
			pw.print(Global.class.getFields()[i].getName());
			pw.print("=");
			pw.print(Global.class.getFields()[i].get(null));
			pw.println();
		}
		pw.close();
		fw.close();
	}

	/**
	 * Read in phase resetting map file specified by the String resettingmap.
	 * The phase resetting map file is a text file contains only values. The
	 * value is phase/2PI. So when we use phase resetting map, we use equation:
	 * new_phase = old_phase + phase_resetting * 2 * PI.
	 * 
	 * @param resettingmap
	 * @throws IOException
	 */
	public static void getResettingMap(String resettingmap) throws IOException {
		File file = new File(resettingmap);
		if (file.exists()) {
			Scanner sc = new Scanner(file);
			ArrayList<Double> rm = new ArrayList<Double>();
			while (sc.hasNext()) {
				rm.add(sc.nextDouble());
			}
			resettingMap = new double[rm.size()];
			for (int i = 0; i < rm.size(); i++) {
				resettingMap[i] = rm.get(i);
			}
		} else {
			System.out.println("Resetting map does not exist!");
		}
	}

	/**
	 * Manually change the shape of the resetting map. REFINE_TYPE == 1: longer
	 * refractory period
	 * 
	 * This method only works with current phase resetting map.
	 * 
	 * @param rmap
	 * @param REFINE_TYPE
	 */
	public static void refineResettingMap(double[] rmap, int REFINE_TYPE) {
		double[] newrmap = new double[rmap.length];
		switch (REFINE_TYPE) {
		case 1:
			System.out.println("Increase refractory period");
			for (int i = 0, j = 0; i < 73; i++, j += 2) {
				newrmap[j] = rmap[i];
				newrmap[j + 1] = rmap[i];

			}
			for (int i = 146; i < newrmap.length; i++) {
				int mapindex = (520 - 73) * (i - 146) / (520 - 146) + 73;
				newrmap[i] = rmap[mapindex];
			}
			break;
		default:
			System.out.println("Did not refine!");
			newrmap = rmap;
			break;
		}
		Global.resettingMap = newrmap;
	}

	/*
	 * {//under construction functions public static void outputData(String
	 * dirname, String datatype, double[] data) throws IOException { String
	 * filename = dirname + "//" + datatype + "." + Global.time + ".txt";
	 * FileWriter fw = new FileWriter(filename); PrintWriter pw = new
	 * PrintWriter(fw); for (int i = 0; i < data.length; i++) {
	 * pw.println(data[i]); } pw.close(); fw.close(); }
	 * 
	 * public static ArrayList<MyxoAgent> getSubList(ArrayList<MyxoAgent> list,
	 * double startx, double endx) { ArrayList<MyxoAgent> sublist = new
	 * ArrayList<MyxoAgent>(); for (int i = 0; i < list.size(); i++) { if
	 * (list.get(i).x > startx && list.get(i).x < endx) {
	 * sublist.add(list.get(i)); } } return sublist; }
	 * 
	 * public static void saveAgentState(String dirname, ArrayList<MyxoAgent>
	 * agentList) throws IOException { String filename = dirname + "//" +
	 * "stats" + ".AgentState" + ".txt"; FileWriter fw = new
	 * FileWriter(filename); PrintWriter pw = new PrintWriter(fw); for (int i =
	 * 0; i < agentList.size(); i++) { pw.print(agentList.get(i).x + "|");
	 * pw.print(agentList.get(i).y + "|"); pw.print(agentList.get(i).dir + "|");
	 * pw.print(agentList.get(i).phase + "|"); pw.print(agentList.get(i).va +
	 * "|"); pw.print(agentList.get(i).w); pw.println(); } pw.close();
	 * fw.close(); }
	 * 
	 * / This method compute average time a cell spend in an area and its
	 * symetric area. The returned array has two values, first one is in left
	 * region, the second one is in right region
	 */
	/*
	 * public static double[] averageTimeInRegion(ArrayList<MyxoAgent> list) {
	 * double[] averageTime = new double[2]; int nleft = 0; int nright = 0; for
	 * (int i = 0; i < list.size(); i++) { if (list.get(i).inLeftRegionTime > 0)
	 * { nleft += 1; averageTime[0] += list.get(i).inLeftRegionTime; } if
	 * (list.get(i).inRightRegionTime > 0) { nright += 1; averageTime[1] +=
	 * list.get(i).inRightRegionTime; } } averageTime[0] /= (double) nleft;
	 * averageTime[1] /= (double) nright; return averageTime; }
	 * 
	 * // Calculate random drift by ini_x public static double
	 * calcStats(ArrayList<MyxoAgent> list) { double sum = 0; double num = 0;
	 * for (int i = 0; i < list.size(); i++) { if (Global.PeBound) { if
	 * (list.get(i).ifCrossBoundary) { continue; } else { sum += (list.get(i).x
	 * - list.get(i).ini_x) (list.get(i).x - list.get(i).ini_x); num += 1.0; } }
	 * else { sum += (list.get(i).x - list.get(i).ini_x) (list.get(i).x -
	 * list.get(i).ini_x); num += 1.0; } } sum /= num; return sum; }
	 * 
	 * public static double calcStatsDifftime(ArrayList<MyxoAgent> list, double
	 * time) { double sum = 0; double num = 0; for (int i = 0; i < list.size();
	 * i++) {
	 * 
	 * if (Global.PeBound) { if (time <= 0.3 Global.s_time) { if
	 * (list.get(i).ifCrossBoundarye) { continue; } else { sum += (list.get(i).x
	 * - list.get(i).ini_xe) (list.get(i).x - list.get(i).ini_xe); num += 1; } }
	 * else if (time <= 0.7 Global.s_time) { if (list.get(i).ifCrossBoundarym) {
	 * continue; } else { sum += (list.get(i).x - list.get(i).ini_xm)
	 * (list.get(i).x - list.get(i).ini_xm); num += 1; } } else { if
	 * (list.get(i).ifCrossBoundaryl) { continue; } else { sum += (list.get(i).x
	 * - list.get(i).ini_xl) (list.get(i).x - list.get(i).ini_xl); num += 1; } }
	 * 
	 * } else {
	 * 
	 * if (time <= 0.3 Global.s_time) { sum += (list.get(i).x -
	 * list.get(i).ini_xe) (list.get(i).x - list.get(i).ini_xe); } else if (time
	 * <= 0.7 Global.s_time) { sum += (list.get(i).x - list.get(i).ini_xm)
	 * (list.get(i).x - list.get(i).ini_xm); } else { sum += (list.get(i).x -
	 * list.get(i).ini_xl) (list.get(i).x - list.get(i).ini_xl); }
	 * 
	 * num += 1; } } sum /= num; return sum; }
	 * 
	 * / Calculate diffcusion coefficient in a certain region. The region is
	 * defined in MyxoAgent.checkCross method. The returned value is a array
	 * contain two element. The first element is the diff co in the left region.
	 * The secon element is the diff co in the right region.
	 */
	/*
	 * public static double computeDiffCoefficientLeft(ArrayList<MyxoAgent>
	 * list, double time) { if (list.size() > 0) { double sum = 0; for (int i =
	 * 0; i < list.size(); i++) { sum += (list.get(i).x - list.get(i).iniXLeft)
	 * (list.get(i).x - list.get(i).iniXLeft); } sum /= (double) list.size();
	 * return sum; } else { return 0; } }
	 * 
	 * public static double computeDiffCoefficientRight(ArrayList<MyxoAgent>
	 * list, double time) { if (list.size() > 0) { double sum = 0; for (int i =
	 * 0; i < list.size(); i++) { sum += (list.get(i).x - list.get(i).iniXRight)
	 * (list.get(i).x - list.get(i).iniXRight); } sum /= (double) list.size();
	 * return sum; } else { return 0; } }
	 * 
	 * public static double calcDiffAveL(ArrayList<MyxoAgent> list, double time)
	 * { if (list.size() > 0) { double sum = 0; int tstep = (int) ((time - 0.8
	 * Global.s_time) / Global.dt); for (int i = 0; i < list.size(); i++) { /
	 * Compute avearge shift
	 */
	/*
	 * list.get(i).aveXleft = (list.get(i).aveXleft (double) tstep + list
	 * .get(i).x) / (double) (tstep + 1); sum += (list.get(i).x -
	 * list.get(i).aveXleft) (list.get(i).x - list.get(i).aveXleft); } sum /=
	 * (double) list.size(); return sum; } else { return 0; } }
	 * 
	 * public static double calcDiffAveR(ArrayList<MyxoAgent> list, double time)
	 * { if (list.size() > 0) { double sum = 0; int tstep = (int) ((time - 0.8
	 * Global.s_time) / Global.dt); for (int i = 0; i < list.size(); i++) { /
	 * Compute avearge shift
	 */
	/*
	 * list.get(i).aveXRight = (list.get(i).aveXRight (double) tstep + list
	 * .get(i).x) / (double) (tstep + 1); sum += (list.get(i).x -
	 * list.get(i).aveXRight) (list.get(i).x - list.get(i).aveXRight); } sum /=
	 * (double) list.size(); return sum; } else { return 0; } }
	 * 
	 * public static double[] calcFlux(ArrayList<MyxoAgent> list, double time) {
	 * double[] flux = new double[4]; for (int i = 0; i < list.size(); i++) { if
	 * (list.get(i).ifCrossLeftin) { flux[0] += 1; list.get(i).ifCrossLeftin =
	 * false; } if (list.get(i).ifCrossLeftout) { flux[1] += 1;
	 * list.get(i).ifCrossLeftout = false; } if (list.get(i).ifCrossRightin) {
	 * flux[2] += 1; list.get(i).ifCrossRightin = false; } if
	 * (list.get(i).ifCrossRightout) { flux[3] += 1; list.get(i).ifCrossRightout
	 * = false; } } return flux; }
	 * 
	 * 
	 * }
	 */

	// public static double colAgentNum;
	
	//simType = 1, Speed is independent (rippling)
	//simType = 2, Speed is dependent on local cell density
	public static double simType;
	
	public static double densityRange;
	
	public static double sigRange;
	
	public static double initialType;

	public static double densityThreshold;
	
	public static double streamSigCoef;
	
	public static double collisionSigCoef;
	
	public static double gradDen0;
	
	public static double velocityChange;
	
	public static double vChangePro;
	
	public static double turn;

	public static double frictionCoefficient;

	public static double saveTimePoint;

	public static double phaseDiffCoef;

	public static double velocityDiffCoef;

	public static double positiveSignalFraction;
	
	public static double alignPro;
	
	public static double threadN;

	// public static double collidingCell;

	public static double averageQualifiedSignalCellNum;
	
	public static double meanDir;

	public static double refractoryPeriod;

	public static double phaseJump;

	public static double phaseJumpProbability;

	public static int collisionType;

	public static int collisionResolveType;

	public static double cellLength;

	public static double cellWidth;

	public static double vAmoter;
	
	public static double lowV;

	public static double vInSlime;

	public static double vSmoter;

	public static double vPhase;
	
	public static double alignToNeighbor;
	
	public static double alignToAggBound;
	
	public static double speedCorrelation;

	public static double reversingTime;

	public static double vPhaseInSlime;

	public static double vReproduct;

	public static double worldX;

	public static double worldY;
	
	public static double originX;
	
	public static double originY;
	
	public static double coneAngle;

	public static double cSiganlStartX;

	public static double cSignalStartY;

	public static double cSiganlWidth;

	public static double cSignalHeight;

	public static double cSignalType;

	public static double dT;

	public static double gridSize;

	public static double pixSize;

	public static int cellNum;

	public static int labeledCellNum;

	public static int refineMapType;

	public static int timeIndex;

	public static int fluxType;

	public static double fluxBoundary;

	public static double boundX;

	public static double boundY;

	public static double boundWidth;

	public static double boundHeight;

	public static double boundCenterX;

	public static double boundCenterY;

	public static double boundR;

	// This method means plot cell every outputNumRatio cells
	public static int outputNumRatio;

	public static double trackStartTime;

	public static double trackEndTime;

	public static double outputDt;

	public static double simTime;

	public static double iniRadius;

	public static double iniWidth;

	public static double iniHeight;

	public static double ringWidth;

	public static double maxNeighborDis;

	public static double maxSlimeDis;

	public static double slimeLife;

	// public static double extend;

	public static double ACP;

	public static double ASP;

	public static double AAP;

	public static double DCP;

	public static double DSP;

	public static double DAP;

	public static double JSP;

	public static double BSP;

	public static double spaceDiffCoef;

	public static double xDiffCoef;

	public static double yDiffCoef;

	public static double dirDiffCoef;

	public static double vPhaseDiffCoef;

	public static double windShield;

	public static double edgeCellFraction;

	public static double currTime;

	public static boolean SMOTOR;

	public static boolean AMOTOR;

	public static boolean IFALIGNED;

	public static boolean SIGNAL;

	public static boolean PERBOUNDX;

	public static boolean PERBOUNDY;

	public static boolean DEBUG;

	public static double[] resettingMap;

	public static double[] distanceExpan;

	public static int[] cellFluxArray;

	public static int[] cellNumberArray;

	public static double[] meanSquareDisplace;
	
	public static double[] msdEarly;
	
	public static double[] msdMiddle;
	
	public static double[] msdLate;

	public static double[] signalTrack;
	
	public static double[] vArray;

	public static String dirName;

	public static String imageDirName;

	public static Random r = new Random();

	public static ArrayList<Double> reverPeriods = new ArrayList<Double>();

	public static ArrayList<Double> distancePerReverse = new ArrayList<Double>();

	public static ArrayList<Double> refractorTime = new ArrayList<Double>();

	public static ArrayList<MyxoAgent> mirrorAgents;

	public static int numCollisions;
	
	public static double localDensity;
	
	public static double averageAlignment;
	
	public static double averageVelocity;

}
